package ljl.bilibili.gateway.controller;

import com.aliyuncs.exceptions.ClientException;
import ljl.bilibili.gateway.service.LoginService;
import ljl.bilibili.gateway.util.JwtUtil;
import ljl.bilibili.gateway.vo.request.MailLoginRequest;
import ljl.bilibili.gateway.vo.request.PasswordLoginRequest;
import ljl.bilibili.gateway.vo.request.PhoneNumberLoginRequest;
import ljl.bilibili.gateway.vo.response.LoginResponse;
import ljl.bilibili.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpCookie;
import org.springframework.http.ResponseCookie;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ServerWebExchange;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Map;

import static ljl.bilibili.gateway.constant.Constant.*;

@RestController
@RequestMapping("/login")
@CrossOrigin(value = "*")
@Slf4j
public class LoginController {
    @Resource
    LoginService loginService;

    /**
     * 登录成功返回放在缓存中的短token和放在http-only-cookie中的长token，失败返回失败响应
     */
    @PostMapping("/passwordLogin")
    public Result<LoginResponse> passwordLogin(@RequestBody PasswordLoginRequest passwordLoginRequest, ServerWebExchange exchange) {
        // 从请求的Cookie中获取sessionId
        String sessionId = exchange.getRequest().getCookies().getFirst(SESSIONID).getValue();
        // 调用登录服务进行登录操作
        Map<String, Object> map = loginService.passwordLogin(passwordLoginRequest, sessionId);
        if (map.size() > 0) {
            // 获取用户ID、短令牌和长令牌
            Integer userId = (Integer) map.get(USERIDENTITY);
            String shortJwt = (String) map.get(SHORT_TOKEN);
            String longJwt = (String) map.get(LONG_TOKEN);
            // 在HTTP响应头中添加短令牌，并在Cookie中添加长令牌
            exchange.getResponse().getHeaders().add(SHORT_TOKEN, shortJwt);
            ResponseCookie cookie = ResponseCookie.from(LONG_TOKEN, longJwt)
                    .httpOnly(true)
                    .path("/")
                    .maxAge(60 * 30)//设置Cookie的有效期为30分钟
                    .build();
            exchange.getResponse().addCookie(cookie);
            return Result.data(new LoginResponse().setStatus(true).setUserId(userId));
        }
        return Result.data(new LoginResponse().setStatus(false));
    }

    /**
     * 处理手机号登录请求的方法
     *
     * @param phoneNumberLoginRequest
     * @param exchange
     * @return
     */
    @PostMapping("/phoneNumberLogin")
    public Result<LoginResponse> phoneNumberLogin(@RequestBody PhoneNumberLoginRequest phoneNumberLoginRequest, ServerWebExchange exchange) {
        //调用服务层方法处理手机号登录逻辑
        Map<String, Object> map = loginService.phoneNumberLogin(phoneNumberLoginRequest);
        if (map != null) {
            //从返回结果中提取用户ID、短令牌和长令牌
            Integer userId = (Integer) map.get(USERIDENTITY);
            String shortJwt = (String) map.get(SHORT_TOKEN);
            String longJwt = (String) map.get(LONG_TOKEN);
            //在HTTP响应头中添加短令牌，并在Cookie中添加长令牌
            exchange.getResponse().getHeaders().add(SHORT_TOKEN, shortJwt);
            ResponseCookie cookie = ResponseCookie.from(LONG_TOKEN, longJwt)
                    .httpOnly(true)
                    .path("/")
                    .maxAge(60 * 30)
                    .build();
            exchange.getResponse().addCookie(cookie);
            log.info("手机号登录的id" + userId);
            return Result.data(new LoginResponse().setStatus(true).setUserId(userId));
        }
        return Result.data(new LoginResponse().setStatus(false));
    }

    /**
     * 处理邮件登录请求的方法
     * 该方法通过邮箱信息进行用户登录，成功后返回登录响应信息，并设置相关cookie
     *
     * @param mailLoginRequest 包含用户邮箱登录信息的请求对象
     * @param exchange         用于获取响应对象，以便添加cookie
     * @return 返回登录结果，包括用户ID和登录状态
     */
    @PostMapping("/mailLogin")
    public Result<LoginResponse> mailLogin(@RequestBody MailLoginRequest mailLoginRequest, ServerWebExchange exchange) {
        //调用服务层方法处理邮件登录逻辑
        Map<String, Object> map = loginService.mailLogin(mailLoginRequest);
        if (map != null) {
            //从返回结果中提取用户ID和JWT令牌
            Integer userId = (Integer) map.get(USERIDENTITY);
            String shortJwt = (String) map.get(SHORT_TOKEN);
            String longJwt = (String) map.get(LONG_TOKEN);
            //在HTTP响应头中添加短令牌，并在Cookie中添加长令牌
            exchange.getResponse().getHeaders().add(SHORT_TOKEN, shortJwt);
            ResponseCookie cookie = ResponseCookie.from(LONG_TOKEN, longJwt)
                    .httpOnly(true)
                    .path("/")
                    .maxAge(60 * 30)
                    .build();
            exchange.getResponse().addCookie(cookie);
            log.info("邮箱登录的id" + userId);
            return Result.data(new LoginResponse().setStatus(true).setUserId(userId));
        }
        return Result.data(new LoginResponse().setStatus(false));
    }

    /**
     * 刷新token
     */
    @PostMapping("/refreshToken")
    public Result<Boolean> refreshToken(ServerWebExchange exchange) {
        log.info("刷新token");
        //从请求头中获取短令牌
        String shortToken = exchange.getRequest().getHeaders().getFirst(SHORT_TOKEN);
        log.info(shortToken);
        //从请求的Cookie中获取长令牌
        String longToken = exchange.getRequest().getCookies().getFirst(LONG_TOKEN).getValue();
        //刷新短令牌和长令牌，并设置到响应头和Cookie中
        exchange.getResponse().getHeaders().set(SHORT_TOKEN, JwtUtil.refreshToken(shortToken, 0));
        ResponseCookie cookie = ResponseCookie.from(LONG_TOKEN, JwtUtil.refreshToken(longToken, 1))
                .httpOnly(true)
                .path("/")
                .maxAge(LONG_TOKEN_EXPIRATION)
                .build();
        exchange.getResponse().addCookie(cookie);
        return Result.success(true);
    }

    /**
     * 获取验证码，并将sessionId返回给客户端，后续刷新验证码时根据sessionId更换redis中验证码值
     */
    @GetMapping("/getCaptcha")
    public Result<String> getCaptcha(ServerWebExchange exchange) throws IOException {
        //获取请求中的Cookie
        HttpCookie cookie = exchange.getRequest().getCookies().getFirst(SESSIONID);
        Map<String, String> map = loginService.getCaptcha(cookie);
        if (map.get(SESSIONID) != null) {
            //将sessionId添加到响应的Cookie中
            ResponseCookie cookies = ResponseCookie.from(SESSIONID, map.get(SESSIONID))
                    .httpOnly(true)
                    .path("/")
                    .maxAge(60 * 30)
                    .build();
            exchange.getResponse().addCookie(cookies);
        }
        // 返回验证码图片数据
        return Result.data(map.get(CAPTCHA_IMAGE));
    }

    /**
     * 发送手机验证码
     */
    @GetMapping("/phoneNumberCaptcha/{phoneNumber}")
    public Result<Boolean> sendPhoneNumberCaptcha(@PathVariable String phoneNumber) throws ClientException {
        return loginService.sendPhoneNumberCaptcha(phoneNumber);
    }

    /**
     * 发送邮箱验证码
     */
    @GetMapping("/mailNumberCaptcha/{mailNumber}")
    public Result<Boolean> sendMailNumberCaptcha(@PathVariable String mailNumber) {

        return loginService.sendMailNumberCaptcha(mailNumber);
    }
}
